package chap_01_CompletableFuture.step_02_CompletableFuture;

import java.util.concurrent.*;

/**
 * @Description 核心的四个静态方法，创建一个异步任务
 * @Author shihan
 * @Date 2022/9/3 18:15
 * @Version 1.0
 */
public class CompletableStudy_01 {

    /**
     * CompletableFuture实现和原生的FutureTask相同的功能（建议使用自定义线程池，不要使用默认的 ForkJoinPool 线程池）
     *
     * @param args
     * @throws ExecutionException
     * @throws InterruptedException
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();

        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // Runnable 的等价方式
        testOne(executorService);

        System.out.println("==================================");

        // Callable 的等价方式
        testTwo(executorService);

        System.out.println("==================================");

        // 线程池的 shutdown 动作测试
        testThree(executorService);

        System.out.println("主程序执行完毕...");
        executorService.shutdown();

    }

    /**
     * 关于线程池 shutdown 的问题：
     * 目前从结果来反推原理：只要线程池中还有待执行的线程，线程池就不会关闭，需要等池中已提交的线程都执行完毕之后才会进行实际的 shutdown 关闭；
     * PS：ForkJoinPool.commonPool() 默认的线程池，在主线程结束后，会自动被关闭，所以要用自定义的线程池来调用 shutdown 等线程执行完
     *
     * @param executorService
     */
    private static void testThree(ExecutorService executorService) {
        Future<?> submit = executorService.submit(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("xxx");
        });
    }

    /**
     * 有返回值的调用方式：指定线程池用指定的，不指定用默认的 ForkJoinPool
     *
     * @param executorService
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void testTwo(ExecutorService executorService) throws InterruptedException, ExecutionException {
        CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> {
            System.out.println("带返回值的线程处理，现在改成Supplier方式的入参格式！");
            return "abc";
        }, executorService);
        System.out.println("Supplier 返回的值（等价于 Callable 方式）：" + completableFuture.get());
        // join()、get() 两个方法都可以获取返回值，只是 join 在编译期间不抛异常（运行时出异常还是会抛异常的），而 get 在编译期间会抛异常
        System.out.println("Supplier 返回的值（等价于 Callable 方式）：" + completableFuture.join());
    }

    /**
     * 没有返回值的调用方式：指定线程池用指定的，不指定用默认的 ForkJoinPool
     *
     * @param executorService
     * @throws InterruptedException
     * @throws ExecutionException
     */
    private static void testOne(ExecutorService executorService) throws InterruptedException, ExecutionException {
        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
            System.out.println("Runnable 没有返回值的处理！");
            System.out.println("不采用默认的 ForkJoinPool.commonPool() 线程池，自己指定线程池！");
        }, executorService);
        System.out.println("Runnable 返回的值：" + voidCompletableFuture.get());
    }

}
